package implementation;

import com.thoughtworks.xstream.XStream;
import entities.Medium;
import entities.MediumType;
import java.util.ArrayList;
import java.util.List;
import managers.MediumManager;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.exist.xmldb.EXistResource;
import org.xmldb.api.base.Collection;
import org.xmldb.api.base.XMLDBException;
import org.xmldb.api.modules.XMLResource;
import utilities.DBUtils;
import utilities.MediumConverter;

/**
 *
 * @author Hacnar
 */
public class MediumManagerImpl implements MediumManager {

    @Override
    public Medium createMedium(Medium medium) {
        
        if (medium == null) {
            throw new IllegalArgumentException("Error: medium is null");
        }
        if (medium.getId() != null) {
            throw new IllegalArgumentException("Error: medium has id");
        }
        
        DBUtils.openDBConnection();
        
        Collection col = null;
        XMLResource res = null;
        try {
            col = DBUtils.getOrCreateCollection("/media");
            
            res = (XMLResource)col.createResource(null, "XMLResource");
            XStream xStream = new XStream();
            xStream.registerConverter(new MediumConverter());
            xStream.alias("medium", Medium.class);
            xStream.useAttributeFor(Medium.class, "lended");
            xStream.useAttributeFor(Medium.class, "type");
            if (!medium.getType().equals(MediumType.FILE)) {
                xStream.useAttributeFor(Medium.class, "title");
            }
            String resXML = xStream.toXML(medium);
            if (!DBUtils.validate(resXML, "utilities/medium.xsd")) {
                Logger.getLogger(MovieManagerImpl.class.getName()).log(Level.WARN, null);
                return medium;
            }
            res.setContent(resXML);
            col.storeResource(res);
            medium.setId(res.getId());
        } catch (XMLDBException ex) {
            Logger.getLogger(MovieManagerImpl.class.getName()).log(Level.ERROR, null, ex);
        }
        finally {
            if(res != null) {
                try { ((EXistResource)res).freeResources(); } catch(XMLDBException ex) {
                    Logger.getLogger(MovieManagerImpl.class.getName()).log(Level.ERROR, null, ex);
                }
            }
            
            if(col != null) {
                try { col.close(); } catch(XMLDBException ex) {
                    Logger.getLogger(MovieManagerImpl.class.getName()).log(Level.ERROR, null, ex);
                }
            }
            DBUtils.closeDB();
        }
        return medium;
    }

    @Override
    public void updateMedium(Medium medium) {
        if (medium == null) {
            throw new IllegalArgumentException("Error: medium is null");
        }
        if (medium.getId() == null) {
            throw new IllegalArgumentException("Error: medium id is not set");
        }
        
        DBUtils.openDBConnection();
        
        Collection col = null;
        XMLResource res = null;
        try { 
            col = DBUtils.getOrCreateCollection("/media");
            res = (XMLResource)col.getResource(medium.getId());
            XStream xStream = new XStream();
            xStream.registerConverter(new MediumConverter());
            xStream.alias("medium", Medium.class);
            xStream.useAttributeFor(Medium.class, "lended");
            xStream.useAttributeFor(Medium.class, "type");
            if (!medium.getType().equals(MediumType.FILE)) {
                xStream.useAttributeFor(Medium.class, "title");
            }
            String resXML = xStream.toXML(medium);
            if (!DBUtils.validate(resXML, "utilities/medium.xsd")) {
                Logger.getLogger(MovieManagerImpl.class.getName()).log(Level.WARN, null);
                return;
            }
            res.setContent(resXML);
            col.storeResource(res);
        } catch (XMLDBException ex) {
            Logger.getLogger(MovieManagerImpl.class.getName()).log(Level.ERROR, null, ex);
        }
        finally {
            if(res != null) {
                try { ((EXistResource)res).freeResources(); } catch(XMLDBException ex) {
                    Logger.getLogger(MovieManagerImpl.class.getName()).log(Level.ERROR, null, ex);
                }
            }
            
            if(col != null) {
                try { col.close(); } catch(XMLDBException ex) {
                    Logger.getLogger(MovieManagerImpl.class.getName()).log(Level.ERROR, null, ex);
                }
            }
            DBUtils.closeDB();
        }
    }

    @Override
    public void deleteMedium(Medium medium) {
        if (medium == null) {
            throw new IllegalArgumentException("Error: medium is null");
        }
        if (medium.getId() == null) {
            throw new IllegalArgumentException("Error: medium id is not set");
        }
        
        DBUtils.openDBConnection();
        
        Collection col = null;
        XMLResource res = null;
        try { 
            col = DBUtils.getOrCreateCollection("/media");
            res = (XMLResource)col.getResource(medium.getId());
            if (res == null) {
                throw new IllegalArgumentException("Error: medium is not in database");
            }
            col.removeResource(res);
        } catch (XMLDBException ex) {
            Logger.getLogger(MovieManagerImpl.class.getName()).log(Level.ERROR, null, ex);
        }
        finally {
            if(res != null) {
                try { ((EXistResource)res).freeResources(); } catch(XMLDBException ex) {
                    Logger.getLogger(MovieManagerImpl.class.getName()).log(Level.ERROR, null, ex);
                }
            }
            if(col != null) {
                try { col.close(); } catch(XMLDBException ex) {
                    Logger.getLogger(MovieManagerImpl.class.getName()).log(Level.ERROR, null, ex);
                }
            }
            DBUtils.closeDB();
        }
    }

    @Override
    public Medium getMediumByID(String id) {
        if (id == null || id.isEmpty()) {
            throw new IllegalArgumentException("Error: id is null or empty");
        }
        DBUtils.openDBConnection();
        Medium medium = null;
        Collection col = null;
        XMLResource res = null;
        try { 
            col = DBUtils.getOrCreateCollection("/media");
            res = (XMLResource)col.getResource(id);
            if (res == null) {
                throw new IllegalArgumentException("Error: medium is not in database");
            }
            XStream xStream = new XStream();
            xStream.registerConverter(new MediumConverter());
            xStream.alias("medium", Medium.class);
            medium = (Medium)xStream.fromXML("<?xml version=\"1.0\"?>"+res.getContent().toString());
            medium.setId(id);
            return medium;
        } catch (XMLDBException ex) {
            Logger.getLogger(MovieManagerImpl.class.getName()).log(Level.ERROR, null, ex);
        }
        finally {
            if(res != null) {
                try { ((EXistResource)res).freeResources(); } catch(XMLDBException ex) {
                    Logger.getLogger(MovieManagerImpl.class.getName()).log(Level.ERROR, null, ex);
                }
            }
            
            if(col != null) {
                try { col.close(); } catch(XMLDBException ex) {
                    Logger.getLogger(MovieManagerImpl.class.getName()).log(Level.ERROR, null, ex);
                }
            }
            DBUtils.closeDB();
        }
        return medium;
    }

    @Override
    public List<Medium> getAllMedia() {
        DBUtils.openDBConnection();
        List<Medium> media = new ArrayList<Medium>();
        try {
            Collection col = DBUtils.getOrCreateCollection("/media");
            String[] ids = col.listResources();
            int count = col.getResourceCount();
            for (int i = 0; i < count; i++) {
                media.add(getMediumByID(ids[i]));
            }
        } catch (XMLDBException ex) {
            Logger.getLogger(MovieManagerImpl.class.getName()).log(Level.ERROR, null, ex);
        } finally {
            DBUtils.closeDB();
        }
        
        return media;
    }
    
}
